home *** CD-ROM | disk | FTP | other *** search
/ PC Open 100 / PC Open 100 CD 1.bin / CD1 / INTERNET / EMAIL / pop file / setup.exe / POPFile / Configuration.pm next >
Encoding:
Perl POD Document  |  2004-08-02  |  18.4 KB  |  626 lines

  1. # POPFILE LOADABLE MODULE
  2. package POPFile::Configuration;
  3.  
  4. use POPFile::Module;
  5. @ISA = ( "POPFile::Module" );
  6.  
  7. #----------------------------------------------------------------------------
  8. #
  9. # This module handles POPFile's configuration parameters.  It is used to
  10. # load and save from the popfile.cfg file and individual POPFile modules
  11. # register specific parameters with this module.  This module also handles
  12. # POPFile's command line parsing
  13. #
  14. # Copyright (c) 2001-2003 John Graham-Cumming
  15. #
  16. #   This file is part of POPFile
  17. #
  18. #   POPFile is free software; you can redistribute it and/or modify
  19. #   it under the terms of the GNU General Public License as published by
  20. #   the Free Software Foundation; either version 2 of the License, or
  21. #   (at your option) any later version.
  22. #
  23. #   POPFile is distributed in the hope that it will be useful,
  24. #   but WITHOUT ANY WARRANTY; without even the implied warranty of
  25. #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26. #   GNU General Public License for more details.
  27. #
  28. #   You should have received a copy of the GNU General Public License
  29. #   along with POPFile; if not, write to the Free Software
  30. #   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  31. #
  32. #----------------------------------------------------------------------------
  33.  
  34. use strict;
  35. use warnings;
  36. use locale;
  37.  
  38. use Getopt::Long;
  39.  
  40. #----------------------------------------------------------------------------
  41. # new
  42. #
  43. #   Class new() function
  44. #----------------------------------------------------------------------------
  45. sub new
  46. {
  47.     my $type = shift;
  48.     my $self = POPFile::Module->new();
  49.  
  50.     # All the current configuration parameters are stored in this hash which
  51.     # is intended to be globally accessed by modules that make use of this module,
  52.     # to register a configuration default entries are made in this hash in the form
  53.     #
  54.     # $self->{configuration_parameters__}{parameter}
  55.     $self->{configuration_parameters__} = {};
  56.  
  57.     # Name of the PID file that we created
  58.  
  59.     $self->{pid_file__} = '';
  60.  
  61.     # The time to delay checking of the PID file
  62.  
  63.     $self->{pid_delay__} = 5;
  64.  
  65.     # The last time the PID was checked
  66.  
  67.     $self->{pid_check__} = time;
  68.  
  69.     # Used to tell whether we need to save the configuration
  70.  
  71.     $self->{save_needed__} = 0;
  72.  
  73.     # Local copies of POPFILE_ROOT and POPFILE_USER
  74.  
  75.     $self->{popfile_root__} = $ENV{POPFILE_ROOT} || './';
  76.     $self->{popfile_user__} = $ENV{POPFILE_USER} || './';
  77.  
  78.     bless $self, $type;
  79.  
  80.     $self->name( 'config' );
  81.  
  82.     return $self;
  83. }
  84.  
  85. # ---------------------------------------------------------------------------------------------
  86. #
  87. # initialize
  88. #
  89. # Called to initialize the interface
  90. #
  91. # ---------------------------------------------------------------------------------------------
  92. sub initialize
  93. {
  94.     my ( $self ) = @_;
  95.  
  96.     # This is the location where we store the PID of POPFile in a file
  97.     # called popfile.pid
  98.  
  99.     $self->config_( 'piddir', './' );
  100.  
  101.     # This counter is used when creating unique IDs for message stored
  102.     # in the history.  The history message files have the format
  103.     #
  104.     # popfile{download_count}={message_count}.msg
  105.     #
  106.     # Where the download_count is derived from this value and the
  107.     # message_count is a local counter within that download, for sorting
  108.     # purposes must sort on download_count and then message_count
  109.     #
  110.     # download_count is incremented every time POPFile forks to
  111.     # start a session for downloading messages (see Proxy::Proxy::service
  112.     # for details)
  113.  
  114.     $self->global_config_( 'download_count', 0 );
  115.  
  116.     # The default timeout in seconds for POP3 commands
  117.  
  118.     $self->global_config_( 'timeout', 60 );
  119.  
  120.     # The default location for the message files
  121.  
  122.     $self->global_config_( 'msgdir', 'messages/' );
  123.  
  124.     # The maximum number of characters to consider in a message during
  125.     # classification, display or reclassification
  126.  
  127.     $self->global_config_( 'message_cutoff', 100000 );
  128.  
  129.     return 1;
  130. }
  131.  
  132. # ---------------------------------------------------------------------------------------------
  133. #
  134. # start
  135. #
  136. # Called to start this module
  137. #
  138. # ---------------------------------------------------------------------------------------------
  139. sub start
  140. {
  141.     my ( $self ) = @_;
  142.  
  143.     # Check to see if the PID file is present, if it is then another POPFile
  144.     # may be running, warn the user and terminate
  145.  
  146.     $self->{pid_file__} = $self->get_user_path( $self->config_( 'piddir' ) . 'popfile.pid', 0 );
  147.  
  148.     if (defined($self->live_check_())) {
  149.         return 0;
  150.     }
  151.  
  152.     $self->write_pid_();
  153.  
  154.     return 1;
  155. }
  156.  
  157. # ---------------------------------------------------------------------------------------------
  158. #
  159. # service
  160. #
  161. # service() is a called periodically to give the module a chance to do housekeeping work.
  162. #
  163. # If any problem occurs that requires POPFile to shutdown service() should return 0 and
  164. # the top level process will gracefully terminate POPFile including calling all stop()
  165. # methods.  In normal operation return 1.#
  166. # ---------------------------------------------------------------------------------------------
  167. sub service
  168. {
  169.     my ( $self ) = @_;
  170.  
  171.     my $time = time;
  172.  
  173.     if ( $self->{pid_check__} <= ( $time - $self->{pid_delay__})) {
  174.  
  175.         $self->{pid_check__} = $time;
  176.  
  177.         if ( !$self->check_pid_() ) {
  178.             $self->write_pid_();
  179.             $self->log_("New POPFile instance detected and signalled")
  180.         }
  181.     }
  182.  
  183.     return 1;
  184. }
  185.  
  186. # ---------------------------------------------------------------------------------------------
  187. #
  188. # stop
  189. #
  190. # Called to shutdown this module
  191. #
  192. # ---------------------------------------------------------------------------------------------
  193. sub stop
  194. {
  195.     my ( $self ) = @_;
  196.  
  197.     $self->save_configuration();
  198.  
  199.     $self->delete_pid_();
  200. }
  201.  
  202. # ---------------------------------------------------------------------------------------------
  203. #
  204. # live_check_
  205. #
  206. # Checks if an instance of POPFile is currently running. Takes 10 seconds.
  207. # Returns the process-ID of the currently running POPFile, undef if none.
  208. #
  209. # ---------------------------------------------------------------------------------------------
  210. sub live_check_
  211. {
  212.     my ( $self ) = @_;
  213.  
  214.     if ( $self->check_pid_() ) {
  215.  
  216.         my $oldpid = $self->get_pid_();
  217.  
  218.         my $error = "\n\nA copy of POPFile appears to be running.\n Attempting to signal the previous copy.\n Waiting " . ($self->{pid_delay__} * 2) . " seconds for a reply.\n";
  219.  
  220.         $self->delete_pid_();
  221.  
  222.         print STDERR $error;
  223.  
  224.         select(undef, undef, undef, ($self->{pid_delay__} * 2));
  225.  
  226.         my $pid = $self->get_pid_();
  227.  
  228.         if (defined($pid)) {
  229.             $error = "\n A copy of POPFile is running.\n It has signaled that it is alive with process ID: $pid\n";
  230.             print STDERR $error;
  231.             return $pid;
  232.         } else {
  233.             print STDERR "\nThe other POPFile ($oldpid) failed to signal back, starting new copy ($$)\n";
  234.     }
  235.     }
  236.     return undef;
  237. }
  238.  
  239. # ---------------------------------------------------------------------------------------------
  240. #
  241. # check_pid_
  242. #
  243. # returns 1 if the pid file exists, 0 otherwise
  244. #
  245. # ---------------------------------------------------------------------------------------------
  246.  
  247. sub check_pid_
  248. {
  249.     my ( $self ) = @_;
  250.     return (-e $self->{pid_file__});
  251. }
  252.  
  253. # ---------------------------------------------------------------------------------------------
  254. #
  255. # get_pid_
  256. #
  257. # returns the pidfile proccess ID if a pid file is present, undef otherwise (0 might be a valid PID)
  258. #
  259. # ---------------------------------------------------------------------------------------------
  260. sub get_pid_
  261. {
  262.     my ( $self ) = @_;
  263.  
  264.     if (open PID, $self->{pid_file__}) {
  265.         my $pid = <PID>;
  266.         $pid =~ s/[\r\n]//g;
  267.         close PID;
  268.         return $pid;
  269.     }
  270.  
  271.     return undef;
  272. }
  273.  
  274. # ---------------------------------------------------------------------------------------------
  275. #
  276. # write_pid_
  277. #
  278. # writes the current process-ID into the pid file
  279. #
  280. # ---------------------------------------------------------------------------------------------
  281. sub write_pid_
  282. {
  283.     my ( $self ) = @_;
  284.  
  285.     if ( open PID, ">$self->{pid_file__}" ) {
  286.         print PID "$$\n";
  287.         close PID;
  288.     }
  289. }
  290.  
  291. # ---------------------------------------------------------------------------------------------
  292. #
  293. # delete_pid_
  294. #
  295. # deletes the pid file
  296. #
  297. # ---------------------------------------------------------------------------------------------
  298. sub delete_pid_
  299. {
  300.     my ( $self ) = @_;
  301.  
  302.     unlink( $self->{pid_file__} );
  303. }
  304.  
  305. # ---------------------------------------------------------------------------------------------
  306. #
  307. # parse_command_line - Parse ARGV
  308. #
  309. # The arguments are the keys of the configuration hash.  Any argument that is not already
  310. # defined in the hash generates an error, there must be an even number of ARGV elements because
  311. # each command argument has to have a value.
  312. #
  313. # ---------------------------------------------------------------------------------------------
  314. sub parse_command_line
  315. {
  316.     my ( $self ) = @_;
  317.  
  318.     # Options from the command line specified with the --set parameter
  319.  
  320.     my @set_options;
  321.  
  322.     # The following command line options are supported:
  323.     #
  324.     # --set          Permanently sets a configuration item for the current user
  325.     # --             Everything after this point is an old style POPFile option
  326.     #
  327.     # So its possible to do
  328.     #
  329.     # --set bayes_param=value --set=-bayes_parem=value --set -bayes_parem=value -- -bayes_parem value
  330.  
  331.     if ( !GetOptions( "set=s" => \@set_options ) ) {
  332.         return 0;
  333.     }
  334.  
  335.     # Join together the options specified with --set and those after the --, the
  336.     # options in @set_options are going to be of the form foo=bar and hence need to
  337.     # be split into foo bar
  338.  
  339.     my @options;
  340.  
  341.     for my $i (0..$#set_options) {
  342.         $set_options[$i] =~ /-?(.+)=(.+)/;
  343.  
  344.     if ( !defined( $1 ) ) {
  345.             print STDERR "\nBad option: $set_options[$i]\n";
  346.             return 0;
  347.     }
  348.  
  349.         push @options, ("-$1");
  350.         if ( defined( $2 ) ) {
  351.             push @options, ($2);
  352.     }
  353.     }
  354.  
  355.     push @options, @ARGV;
  356.  
  357.     if ( $#options >= 0 )  {
  358.         my $i = 0;
  359.  
  360.         while ( $i <= $#options )  {
  361.             # A command line argument must start with a -
  362.  
  363.             if ( $options[$i] =~ /^-(.+)$/ ) {
  364.                 my $parameter = $self->upgrade_parameter__($1);
  365.  
  366.                 if ( defined($self->{configuration_parameters__}{$parameter}) ) {
  367.                     if ( $i < $#options ) {
  368.                         $self->parameter( $parameter, $options[$i+1] );
  369.                         $i += 2;
  370.                     } else {
  371.                         print STDERR "\nMissing argument for $options[$i]\n";
  372.                         return 0;
  373.                     }
  374.                 } else {
  375.                     print STDERR "\nUnknown option $options[$i]\n";
  376.                     return 0;
  377.                 }
  378.             } else {
  379.                 print STDERR "\nExpected a command line option and got $options[$i]\n";
  380.                 return 0;
  381.             }
  382.         }
  383.     }
  384.  
  385.     return 1;
  386. }
  387.  
  388. # ---------------------------------------------------------------------------------------------
  389. #
  390. # upgrade_parameter__
  391. #
  392. # Given a parameter from either command line or from the configuration file return the
  393. # upgraded version (e.g. the old port parameter becomes pop3_port
  394. #
  395. # ---------------------------------------------------------------------------------------------
  396.  
  397. sub upgrade_parameter__
  398. {
  399.     my ( $self, $parameter ) = @_;
  400.  
  401.     # This table maps from the old parameter to the new one, for example the old
  402.     # xpl parameter which controls insertion of the X-POPFile-Link header in email
  403.     # is now called GLOBAL_xpl and is accessed through POPFile::Module::global_config_
  404.     # The old piddir parameter is now config_piddir and is accessed through either config_
  405.     # if accessed from the config module or through module_config_ from outside
  406.  
  407.     my %upgrades = ( # PROFILE BLOCK START
  408.  
  409.                      # Parameters that are now handled by Classifier::Bayes
  410.  
  411.                      'corpus',                   'bayes_corpus',
  412.                      'unclassified_probability', 'bayes_unclassified_probability',
  413.  
  414.                      # Parameters that are now handled by POPFile::Configuration
  415.  
  416.                      'piddir',                   'config_piddir',
  417.  
  418.                      # Parameters that are now global to POPFile
  419.  
  420.                      'debug',                    'GLOBAL_debug',
  421.                      'msgdir',                   'GLOBAL_msgdir',
  422.                      'timeout',                  'GLOBAL_timeout',
  423.                      'download_count',           'GLOBAL_download_count',
  424.  
  425.                      # Parameters that are now handled by POPFile::Logger
  426.  
  427.                      'logdir',                   'logger_logdir',
  428.  
  429.                      # Parameters that are now handled by Proxy::POP3
  430.  
  431.                      'localpop',                 'pop3_local',
  432.                      'port',                     'pop3_port',
  433.                      'sport',                    'pop3_secure_port',
  434.                      'server',                   'pop3_secure_server',
  435.                      'separator',                'pop3_separator',
  436.                      'toptoo',                   'pop3_toptoo',
  437.  
  438.                      # Parameters that are now handled by UI::HTML
  439.  
  440.                      'archive',                  'html_archive',
  441.                      'archive_classes',          'html_archive_classes',
  442.                      'archive_dir',              'html_archive_dir',
  443.                      'history_days',             'html_history_days',
  444.                      'language',                 'html_language',
  445.                      'last_reset',               'html_last_reset',
  446.                      'last_update_check',        'html_last_update_check',
  447.                      'localui',                  'html_local',
  448.                      'page_size',                'html_page_size',
  449.                      'password',                 'html_password',
  450.                      'send_stats',               'html_send_stats',
  451.                      'skin',                     'html_skin',
  452.                      'test_language',            'html_test_language',
  453.                      'update_check',             'html_update_check',
  454.                      'ui_port',                  'html_port',
  455.     ); # PROFILE BLOCK STOP
  456.  
  457.     if ( defined( $upgrades{$parameter} ) ) {
  458.         return $upgrades{$parameter};
  459.     } else {
  460.         return $parameter;
  461.     }
  462. }
  463.  
  464. # ---------------------------------------------------------------------------------------------
  465. #
  466. # load_configuration
  467. #
  468. # Loads the current configuration of popfile into the configuration hash from a local file.
  469. # The format is a very simple set of lines containing a space separated name and value pair
  470. #
  471. # ---------------------------------------------------------------------------------------------
  472. sub load_configuration
  473. {
  474.     my ( $self ) = @_;
  475.  
  476.     if ( open CONFIG, '<' . $self->get_user_path( 'popfile.cfg' ) ) {
  477.         while ( <CONFIG> ) {
  478.             s/(\015|\012)//g;
  479.             if ( /(\S+) (.+)?/ ) {
  480.                 my $parameter = $1;
  481.                 my $value     = $2;
  482.                 $value = '' if !defined( $value );
  483.  
  484.                 $parameter = $self->upgrade_parameter__($parameter);
  485.  
  486.                 if ( defined( $self->{configuration_parameters__}{$parameter} ) ) {
  487.                     $self->{configuration_parameters__}{$parameter} = $value;
  488.             } else {
  489.                     $self->log_( "Discarded unknown parameter '$parameter' from popfile.cfg" );
  490.                     $self->{deprecated_parameters__}{$parameter} = $value;
  491.                 }
  492.             }
  493.         }
  494.  
  495.         close CONFIG;
  496.     }
  497.  
  498.     $self->{save_needed__} = 0;
  499. }
  500.  
  501. # ---------------------------------------------------------------------------------------------
  502. #
  503. # save_configuration
  504. #
  505. # Saves the current configuration of popfile from the configuration hash to a local file.
  506. #
  507. # ---------------------------------------------------------------------------------------------
  508. sub save_configuration
  509. {
  510.     my ( $self ) = @_;
  511.  
  512.     if ( $self->{save_needed__} == 0 ) {
  513.         return;
  514.     }
  515.  
  516.     if ( open CONFIG, '>' . $self->get_user_path( 'popfile.cfg' ) ) {
  517.         $self->{save_needed__} = 0;
  518.  
  519.         foreach my $key (sort keys %{$self->{configuration_parameters__}}) {
  520.             print CONFIG "$key $self->{configuration_parameters__}{$key}\n";
  521.         }
  522.  
  523.         close CONFIG;
  524.     }
  525. }
  526.  
  527. # ---------------------------------------------------------------------------------------------
  528. #
  529. # get_user_path, get_root_path
  530. #
  531. # Resolve a path relative to POPFILE_USER or POPFILE_ROOT
  532. #
  533. # $path              The path to resolve
  534. #
  535. # ---------------------------------------------------------------------------------------------
  536. sub get_user_path
  537. {
  538.     my ( $self, $path, $sandbox ) = @_;
  539.  
  540.     return $self->path_join__( $self->{popfile_user__}, $path, $sandbox );
  541. }
  542.  
  543. sub get_root_path
  544. {
  545.     my ( $self, $path, $sandbox ) = @_;
  546.  
  547.     return $self->path_join__( $self->{popfile_root__}, $path, $sandbox );
  548. }
  549.  
  550. # ---------------------------------------------------------------------------------------------
  551. #
  552. # path_join__
  553. #
  554. # Join two paths togther
  555. #
  556. # $left                The LHS
  557. # $right               The RHS
  558. #
  559. # ---------------------------------------------------------------------------------------------
  560. sub path_join__
  561. {
  562.     my ( $self, $left, $right, $sandbox ) = @_;
  563.  
  564.     $sandbox = 1 if ( !defined( $sandbox ) );
  565.  
  566.     if ( ( $right =~ /^\// ) || ( $right =~ /^[A-Za-z]:[\/\\]/ ) ) {
  567.         if ( $sandbox ) {
  568.             return undef;
  569.     } else {
  570.         return $right;
  571.     }
  572.     }
  573.  
  574.     if ( $sandbox && ( $right =~ /\.\./ ) ) {
  575.         return undef;
  576.     }
  577.  
  578.     $left  =~ s/\/$//;
  579.     $right =~ s/^\///;
  580.  
  581.     return "$left/$right";
  582. }
  583.  
  584. # ---------------------------------------------------------------------------------------------
  585. #
  586. # parameter
  587. #
  588. # Gets or sets a parameter
  589. #
  590. # $name          Name of the parameter to get or set
  591. # $value         Optional value to set the parameter to
  592. #
  593. # Always returns the current value of the parameter
  594. #
  595. # ---------------------------------------------------------------------------------------------
  596. sub parameter
  597. {
  598.   my ( $self, $name, $value ) = @_;
  599.  
  600.   if ( defined( $value ) ) {
  601.     $self->{save_needed__} = 1;
  602.     $self->{configuration_parameters__}{$name} = $value;
  603.   }
  604.  
  605.   return $self->{configuration_parameters__}{$name};
  606. }
  607.  
  608. # GETTERS
  609.  
  610. sub configuration_parameters
  611. {
  612.     my ( $self ) = @_;
  613.  
  614.     return sort keys %{$self->{configuration_parameters__}};
  615. }
  616.  
  617. sub deprecated_parameter
  618. {
  619.     my ( $self, $name ) = @_;
  620.  
  621.     return $self->{deprecated_parameters__}{$name};
  622. }
  623.  
  624. 1;
  625.  
  626.